Codepipelineで別アカウントにあるCodeCommitを使用してCI/CD設定をしてみた
Codepipelineを設定中に別AWSアカウントにあるCodeCommitを使用する機会があったのでブログに残します。
やること
AWSアカウントAにあるCodeCommitにgit pushされたらAWSアカウントBにあるCodePipelineを使用してEC2に自動デプロイする構成を作成します。
簡単にはなりますが構成図は以下になります。
AWSアカウントAにあるCodeCommitにgit pushするとEventBridgeで検知してAWSアカウントBにあるEventBridge Busに連携する構成としています。
構成図には記載していませんが、アーティファクト用のS3バケットとKMSキーをAWSアカウントBに作成しています。
CodePipelineからCodeCommitへアクセスするためAWSアカウントAにクロスアカウントIAMロールを作成します。
こちらのIAMロールの内容は以下のブログを参考に設定しています。
かなり細かく説明が記載されているのでご確認いただければと思います。
作成してみた
AWSアカウントBでデプロイ先のEC2、アーティファクト用S3、CodePipelineの使用するIAMロール作成
まずはAWSアカウントAでデプロイ先のEC2などを作成していきます。
リソース作成は以下のCloudFormationで行っています。
CloudFormationテンプレート (ここをクリックしてください)
AWSTemplateFormatVersion: "2010-09-09" Description: CI/CD test Stack Metadata: # ------------------------------------------------------------# # Metadata # ------------------------------------------------------------# AWS::CloudFormation::Interface: ParameterGroups: - Label: default: Parameters for Policy Parameters: - AccountAId - Label: default: Parameters for VPC Parameters: - VPCCIDR - Label: default: Parameters for Subnet Parameters: - PublicSubnet01CIDR - Label: default: Parameters for ec2 Parameters: - EC2VolumeSize - EC2VolumeIOPS - EC2AMI - EC2InstanceType Parameters: # ------------------------------------------------------------# # Parameters # ------------------------------------------------------------# AccountAId: Type: String VPCCIDR: Default: 172.30.0.0/16 Type: String PublicSubnet01CIDR: Default: 172.30.3.0/24 Type: String EC2VolumeSize: Default: 32 Type: Number EC2VolumeIOPS: Default: 3000 Type: Number EC2AMI: Default: '/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-6.1-x86_64' Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id> EC2InstanceType: Default: t3.micro Type: String Resources: # ------------------------------------------------------------# # S3 # ------------------------------------------------------------# S3: Type: AWS::S3::Bucket Properties: BucketEncryption: ServerSideEncryptionConfiguration: - ServerSideEncryptionByDefault: SSEAlgorithm: AES256 BucketName: !Sub ${AWS::StackName}-${AWS::AccountId}-artifact OwnershipControls: Rules: - ObjectOwnership: BucketOwnerEnforced PublicAccessBlockConfiguration: BlockPublicAcls: True BlockPublicPolicy: True IgnorePublicAcls: True RestrictPublicBuckets: True Tags: - Key: Name Value: !Sub ${AWS::StackName}-${AWS::AccountId}-artifact S3ArtifactBucketPolicy: Type: AWS::S3::BucketPolicy Properties: Bucket: !Ref S3 PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: s3:ListBucket Resource: !Sub arn:aws:s3:::${S3} Principal: AWS: - !Sub arn:aws:iam::${AccountAId}:root - Effect: Allow Action: - s3:Get* - s3:Put* Resource: !Sub arn:aws:s3:::${S3}/* Principal: AWS: - !Sub arn:aws:iam::${AccountAId}:root - Effect: Deny Action: s3:PutObject Resource: !Sub arn:aws:s3:::${S3}/* Principal: "*" Condition: StringNotEquals: s3:x-amz-server-side-encryption: aws:kms - Effect: Deny Action: s3:* Resource: !Sub arn:aws:s3:::${S3}/* Principal: "*" Condition: Bool: aws:SecureTransport: false # ------------------------------------------------------------# # IAM # ------------------------------------------------------------# EC2IAMPolicy: Type: AWS::IAM::ManagedPolicy Properties: PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - "s3:GetObject" - "s3:ListBucket" Resource: - !Join - '' - - !GetAtt S3.Arn - '/*' - !GetAtt S3.Arn ManagedPolicyName: iam-policy-deploy-ec2-al2023 EC2IAMRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Service: - ec2.amazonaws.com Action: - 'sts:AssumeRole' ManagedPolicyArns: - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore - !Ref EC2IAMPolicy RoleName: iam-role-ec2-al2023 Tags: - Key: Name Value: iam-role-ec2-al2023 EC2IAMInstanceProfile: Type: AWS::IAM::InstanceProfile Properties: InstanceProfileName: iam-instanceprofile-ec2-al2023 Roles: - !Ref EC2IAMRole CodeBuildIAMPolicy: Type: AWS::IAM::ManagedPolicy Properties: PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - 's3:PutObject' - 's3:GetObject' Resource: - !Join - '' - - !GetAtt S3.Arn - '/*' - Effect: Allow Action: - 'codecommit:GitPull' Resource: "*" - Effect: Allow Action: - 'logs:CreateLogGroup' - 'logs:CreateLogStream' - 'logs:PutLogEvents' Resource: "*" ManagedPolicyName: iam-policy-codebuild CodeBuildIAMRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Service: - codebuild.amazonaws.com Action: - 'sts:AssumeRole' ManagedPolicyArns: - !Ref CodeBuildIAMPolicy RoleName: iam-role-codebuild Tags: - Key: Name Value: iam-role-codebuild CodeDeployIAMRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Service: - codedeploy.amazonaws.com Action: - 'sts:AssumeRole' ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AWSCodeDeployRole RoleName: iam-role-codedeploy Tags: - Key: Name Value: iam-role-codedeploy CodePipelineIAMPolicy: Type: AWS::IAM::ManagedPolicy Properties: PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - "codebuild:BatchGetBuilds" - "codebuild:StartBuild" Resource: - "*" - Effect: Allow Action: - "codedeploy:CreateDeployment" - "codedeploy:GetApplication" - "codedeploy:GetApplicationRevision" - "codedeploy:GetDeployment" - "codedeploy:GetDeploymentConfig" - "codedeploy:RegisterApplicationRevision" Resource: - "*" - Effect: Allow Action: - "s3:GetObject" - "s3:PutObject" - "s3:ListBucket" Resource: - !Join - '' - - !GetAtt S3.Arn - '/*' - !GetAtt S3.Arn - Effect: Allow Action: - sts:AssumeRole Resource: - !Sub arn:aws:iam::${AccountAId}:role/* ManagedPolicyName: iam-policy-codepipeline CodePipelineIAMRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Service: - codepipeline.amazonaws.com Action: - 'sts:AssumeRole' ManagedPolicyArns: - !Ref CodePipelineIAMPolicy RoleName: iam-role-codepipeline Tags: - Key: Name Value: iam-role-codepipeline # ------------------------------------------------------------# # KMS # ------------------------------------------------------------# KMSKey: Type: AWS::KMS::Key Properties: KeyPolicy: Version: "2012-10-17" Id: key-policy Statement: - Effect: Allow Action: kms:* Sid: Enable IAM User Permissions Principal: AWS: - !Sub arn:aws:iam::${AWS::AccountId}:root Resource: "*" - Effect: Allow Action: - kms:DescribeKey - kms:Encrypt - kms:Decrypt - kms:ReEncrypt* - kms:GenerateDataKey - kms:GenerateDataKeyWithoutPlaintext Sid: Allow use of the key Principal: AWS: - !Sub arn:aws:iam::${AccountAId}:root - !GetAtt CodeBuildIAMRole.Arn - !GetAtt CodePipelineIAMRole.Arn - !GetAtt EC2IAMRole.Arn Resource: "*" - Effect: Allow Sid: Allow attachment of persistent resources Action: - kms:CreateGrant - kms:ListGrants - kms:RevokeGrant Principal: AWS: - !Sub arn:aws:iam::${AccountAId}:root - !GetAtt CodeBuildIAMRole.Arn - !GetAtt CodePipelineIAMRole.Arn - !GetAtt EC2IAMRole.Arn Resource: "*" Condition: Bool: kms:GrantIsForAWSResource: true KMSAlias: Type: AWS::KMS::Alias Properties: AliasName: alias/CodePipelineS3Bucket TargetKeyId: Ref: KMSKey # ------------------------------------------------------------# # VPC # ------------------------------------------------------------# VPC: Type: AWS::EC2::VPC Properties: CidrBlock: !Ref VPCCIDR EnableDnsSupport: true EnableDnsHostnames: true Tags: - Key: Name Value: test-vpc # ------------------------------------------------------------# # InternetGateway # ------------------------------------------------------------# InternetGateway: Type: AWS::EC2::InternetGateway Properties: Tags: - Key: Name Value: !Sub test-igw InternetGatewayAttachment: Type: AWS::EC2::VPCGatewayAttachment Properties: InternetGatewayId: !Ref InternetGateway VpcId: !Ref VPC # ------------------------------------------------------------# # Subnet # ------------------------------------------------------------# PublicSubnet01: Type: AWS::EC2::Subnet Properties: AvailabilityZone: ap-northeast-1a CidrBlock: !Ref PublicSubnet01CIDR MapPublicIpOnLaunch: true Tags: - Key: Name Value: !Sub test-public-subnet-01 VpcId: !Ref VPC # ------------------------------------------------------------# # RouteTable # ------------------------------------------------------------# PublicRouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC Tags: - Key: Name Value: test-public-rtb PublicRouteTableRoute: Type: AWS::EC2::Route Properties: DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref InternetGateway RouteTableId: !Ref PublicRouteTable PublicRtAssociation1: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref PublicRouteTable SubnetId: !Ref PublicSubnet01 # ------------------------------------------------------------# # Security Group # ------------------------------------------------------------# EC2SG: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: for ec2 GroupName: test-sg-ec2 SecurityGroupEgress: - CidrIp: 0.0.0.0/0 FromPort: -1 IpProtocol: -1 ToPort: -1 SecurityGroupIngress: - FromPort: 80 IpProtocol: tcp CidrIp: 0.0.0.0/0 ToPort: 80 Tags: - Key: Name Value: test-sg-ec2 VpcId: !Ref VPC # ------------------------------------------------------------# # EC2 # ------------------------------------------------------------# EC2: Type: AWS::EC2::Instance Properties: BlockDeviceMappings: - DeviceName: /dev/xvda Ebs: DeleteOnTermination: true Encrypted: true Iops: !Ref EC2VolumeIOPS VolumeSize: !Ref EC2VolumeSize VolumeType: gp3 DisableApiTermination: false IamInstanceProfile: !Ref EC2IAMInstanceProfile ImageId: !Ref EC2AMI InstanceType: !Ref EC2InstanceType NetworkInterfaces: - AssociatePublicIpAddress: true DeleteOnTermination: true DeviceIndex: 0 GroupSet: - !Ref EC2SG SubnetId: !Ref PublicSubnet01 Tags: - Key: Name Value: test-ec2 UserData: !Base64 | #!/bin/bash yum update yum install ruby -y yum install wget -y wget https://aws-codedeploy-ap-northeast-1.s3.ap-northeast-1.amazonaws.com/latest/install cd chmod +x ./install ./install auto service codedeploy-agent start yum install httpd -y echo "CodeDeploy Test" > /var/www/html/index.html systemctl start httpd systemctl enable httpd Outputs: # ------------------------------------------------------------# # Outputs # ------------------------------------------------------------# CodeBuildIAMRoleARN: Value: !GetAtt CodeBuildIAMRole.Arn Export: Name: iam-role-codebuild-arn CodeDeployIAMRoleARN: Value: !GetAtt CodeDeployIAMRole.Arn Export: Name: iam-role-codedeploy-arn CodePipelineIAMRoleARN: Value: !GetAtt CodePipelineIAMRole.Arn Export: Name: iam-role-codepipeline-arn S3Name: Value: !Ref S3 Export: Name: S3Name
66~120行目でアーティファクト用S3バケットを作成しています。
アーティファクト用S3バケットはAWSアカウントAからアクセスできるようにするためにバケットポリシーを設定しています。
125~292行目でEC2やCodePipelineで使用するIAMロールを作成しています。
IAMロールで重要になるのが、CodePipelineでAWSアカウントAのCodeCommitへアクセスするためにAssumeRoleを行えるポリシーを設定しています。(268~272行目)
297~348行目でKMSキーを作成しています。
KMSキーはキーポリシーでCodePipelineのIAMロール、CodeBuildのIAMロール、EC2のIAMロールとAWSアカウントAからアクセスできるように設定してます。
EC2やVPCの詳細な説明は省かせていただきますが、353~481行目で作成を行っています。
デプロイは以下のAWS CLIコマンドを使用します。
VPCやサブネットのCIDRを変更したい場合は「--parameters」オプションでパラメータを指定してください。
aws cloudformation create-stack --stack-name CloudFormationスタック名 --template-body file://CloudFormationテンプレートファイル名 --parameters ParameterKey=AccountAId,ParameterValue=AWSアカウントAのID --capabilities CAPABILITY_NAMED_IAM
AWSアカウントAでCodeCommitアクセス用IAMロール、CodeCommit、EventBridgeルールの作成
AWSアカウントBでEC2などが作成できたらAWSアカウントAでCodeCommitなどを作成します。
リソース作成は以下のCloudFormationで行っています。
CloudFormationテンプレート (ここをクリックしてください)
AWSTemplateFormatVersion: "2010-09-09" Description: CodeCommit Stack Metadata: # ------------------------------------------------------------# # Metadata # ------------------------------------------------------------# AWS::CloudFormation::Interface: ParameterGroups: - Label: default: Parameters for Policy Parameters: - AccountBId - KMSARN - ArtifactS3ARN - Label: default: Parameters for CodeCommit Parameters: - RepositoryDescription - RepositoryName Parameters: # ------------------------------------------------------------# # Parameters # ------------------------------------------------------------# AccountBId: Type: String KMSARN: Type: String ArtifactS3ARN: Type: String RepositoryDescription: MaxLength: 4000 Type: String RepositoryName: MaxLength: 100 Type: String Resources: # ------------------------------------------------------------# # IAM # ------------------------------------------------------------# EventBridgeIAMPolicy: Type: AWS::IAM::ManagedPolicy Properties: PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - "events:PutEvents" Resource: - !Sub arn:aws:events:${AWS::Region}:${AccountBId}:event-bus/codepipeline ManagedPolicyName: iam-policy-eventbridge EventBridgeIAMRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Service: - events.amazonaws.com Action: - 'sts:AssumeRole' ManagedPolicyArns: - !Ref EventBridgeIAMPolicy RoleName: iam-role-eventbridge Tags: - Key: Name Value: iam-role-eventbridge CodePipelineAssumePolicy: Type: AWS::IAM::ManagedPolicy Properties: PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - "s3:PutObject" - "s3:PutObjectAcl" Resource: - !Sub ${ArtifactS3ARN}/* - Effect: Allow Action: - "kms:DescribeKey" - "kms:GenerateDataKey*" - "kms:Encrypt" - "kms:ReEncrypt*" - "kms:Decrypt" Resource: - !Sub ${KMSARN} - Effect: Allow Action: - "codecommit:GetBranch" - "codecommit:GetCommit" - "codecommit:UploadArchive" - "codecommit:GetUploadArchiveStatus" - "codecommit:CancelUploadArchive" Resource: - !GetAtt CodeCommit.Arn ManagedPolicyName: iam-policy-codepipelineassume CodePipelineAssumeRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: AWS: - !Sub arn:aws:iam::${AccountBId}:root Action: - sts:AssumeRole ManagedPolicyArns: - !Ref CodePipelineAssumePolicy RoleName: iam-role-codepipelineassumerole Tags: - Key: Name Value: iam-role-codepipelineassumerole # ------------------------------------------------------------# # CodeCommit # ------------------------------------------------------------# CodeCommit: Type: AWS::CodeCommit::Repository Properties: RepositoryDescription: !Ref RepositoryDescription RepositoryName: !Ref RepositoryName # ------------------------------------------------------------# # EventBridge # ------------------------------------------------------------# EventBridge: Type: AWS::Events::Rule Properties: Description: for codepipeline EventPattern: source: - aws.codecommit detail-type: - 'CodeCommit Repository State Change' resources: - !GetAtt CodeCommit.Arn detail: event: - referenceCreated - referenceUpdated referenceType: - branch referenceName: - main Name: eventbridge-codepipeline-cross-account State: ENABLED Targets: - Arn: !Sub arn:aws:events:${AWS::Region}:${AccountBId}:event-bus/codepipeline RoleArn: !GetAtt EventBridgeIAMRole.Arn Id: EventBridge Outputs: # ------------------------------------------------------------# # Outputs # ------------------------------------------------------------# CodeCommitRepositoryName: Value: !GetAtt CodeCommit.Name Export: Name: codecommit-repository-name CodeCommitRepositoryARN: Value: !GetAtt CodeCommit.Arn Export: Name: codecommit-repository-arn
48~129行目でEventBridgeとCodeCommitへアクセスするためのIAMロールを作成しています。
EventBridgeのIAMロールに設定するIAMポリシーはAWSアカウントBのEventBridge Busへイベントを送れるように"events:PutEvents"を許可しています。
CodeCommitアクセス用IAMロールはAWSアカウントBのCodePipelineからアクセスできるように信頼ポリシーでAWSアカウントBからのアクセスを許可しています。
134~138行目でCodeCommitを作成しています。
143~167行目でEventBridgeルールを作成しています。
EventBridgeルールではCodeCommitのmainブランチで変更があった時に反応するように設定しています。
また、ターゲットとしてAWSアカウントBのEventBridge Busを設定しています。
デプロイは以下のAWS CLIコマンドを使用します。
aws cloudformation create-stack --stack-name CloudFormationスタック名 --template-body file://CloudFormationテンプレートファイル名 --parameters ParameterKey=AccountBId,ParameterValue=AWSアカウントBのID ParameterKey=KMSARN,ParameterValue=AWSアカウントAで作成したKMSキーのARN ParameterKey=ArtifactS3ARN,ParameterValue=アーティファクト用S3バケットARN ParameterKey=RepositoryDescription,ParameterValue=CodeCommitリポジトリの説明 ParameterKey=RepositoryName,ParameterValue=CodeCommitリポジトリ名 --capabilities CAPABILITY_NAMED_IAM
AWSアカウントBでCodeBuild、CodeDeploy、CodePipeline、EventBridgeの作成
最後にAWSアカウントBでCodePipelineなどを作成していきます。
リソース作成は以下のCloudFormationで行っています。
CloudFormationテンプレート (ここをクリックしてください)
AWSTemplateFormatVersion: "2010-09-09" Description: CodeBuild Stack Metadata: # ------------------------------------------------------------# # Metadata # ------------------------------------------------------------# AWS::CloudFormation::Interface: ParameterGroups: - Label: default: Parameters for CodeBuild Parameters: - CodeBuildDescription - CodeBuildName - Label: default: Parameters for CodeDeploy Parameters: - ApplicationName - DeploymentGroupName - Label: default: Parameters for CodePipeline Parameters: - KMSARN - CodePipelineName - CodeCommitName - CodePipelineAssumeRole - Label: default: Parameters for EventBridge Parameters: - AccountAId Parameters: # ------------------------------------------------------------# # Parameters # ------------------------------------------------------------# CodeBuildDescription: MaxLength: 255 Type: String CodeBuildName: MaxLength: 255 Type: String ApplicationName: MaxLength: 100 Type: String DeploymentGroupName: MaxLength: 100 Type: String KMSARN: Type: String CodePipelineName: MaxLength: 100 Type: String CodeCommitName: Type: String CodePipelineAssumeRole: Type: String AccountAId: Type: String Resources: # ------------------------------------------------------------# # CodeBuild # ------------------------------------------------------------# CodeBuild: Type: AWS::CodeBuild::Project Properties: Artifacts: Type: CODEPIPELINE Description: !Ref CodeBuildDescription EncryptionKey: alias/CodePipelineS3Bucket Environment: ComputeType: BUILD_GENERAL1_SMALL Image: aws/codebuild/amazonlinux2-x86_64-standard:5.0 Type: LINUX_CONTAINER Name: !Ref CodeBuildName ServiceRole: !ImportValue iam-role-codebuild-arn Source: BuildSpec: buildspec.yml Type: CODEPIPELINE Tags: - Key: Name Value: test-build # ------------------------------------------------------------# # CodeDeploy # ------------------------------------------------------------# CodeDeployApplication: Type: AWS::CodeDeploy::Application Properties: ApplicationName: !Ref ApplicationName ComputePlatform: Server Tags: - Key: Name Value: !Ref ApplicationName CodeDeployGroup: Type: AWS::CodeDeploy::DeploymentGroup Properties: ApplicationName: !Ref CodeDeployApplication AutoRollbackConfiguration: Enabled: true Events: - DEPLOYMENT_FAILURE DeploymentConfigName: CodeDeployDefault.AllAtOnce DeploymentGroupName: !Ref DeploymentGroupName Ec2TagFilters: - Key: Name Type: KEY_AND_VALUE Value: test-ec2 ServiceRoleArn: !ImportValue iam-role-codedeploy-arn Tags: - Key: Name Value: !Ref DeploymentGroupName # ------------------------------------------------------------# # CodePipeline # ------------------------------------------------------------# CodePipeline: Type: AWS::CodePipeline::Pipeline Properties: ArtifactStore: Location: !ImportValue S3Name Type: S3 EncryptionKey: Id: !Ref KMSARN Type: KMS Name: !Ref CodePipelineName RoleArn: !ImportValue iam-role-codepipeline-arn Stages: - Actions: - ActionTypeId: Category: Source Owner: AWS Provider: CodeCommit Version: 1 Configuration: RepositoryName: !Ref CodeCommitName BranchName: main PollForSourceChanges: false OutputArtifactFormat: CODE_ZIP Name: Source Namespace: SourceVariables OutputArtifacts: - Name: SourceArtifact Region: ap-northeast-1 RunOrder: 1 RoleArn: !Ref CodePipelineAssumeRole Name: Source - Actions: - ActionTypeId: Category: Build Owner: AWS Provider: CodeBuild Version: 1 Configuration: ProjectName: !Ref CodeBuildName InputArtifacts: - Name: SourceArtifact Name: Build Namespace: BuildVariables OutputArtifacts: - Name: BuildArtifact Region: ap-northeast-1 RunOrder: 1 Name: Build - Actions: - ActionTypeId: Category: Deploy Owner: AWS Provider: CodeDeploy Version: 1 Configuration: ApplicationName: !Ref ApplicationName DeploymentGroupName: !Ref DeploymentGroupName Name: Deploy Namespace: DeployVariables InputArtifacts: - Name: BuildArtifact Region: ap-northeast-1 RunOrder: 1 Name: Deploy Tags: - Key: Name Value: !Ref CodePipelineName # ------------------------------------------------------------# # EventBridge # ------------------------------------------------------------# EventBus: Type : AWS::Events::EventBus Properties: Name: codepipeline EventBusPolicy: Type: AWS::Events::EventBusPolicy Properties: StatementId: !Sub codepipeline EventBusName: codepipeline Statement: Effect: Allow Action: events:PutEvents Resource: !GetAtt EventBus.Arn Principal: AWS: !Sub arn:aws:iam::${AccountAId}:root EventBridgeIAMPolicy: Type: AWS::IAM::ManagedPolicy Properties: PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - "codepipeline:StartPipelineExecution" Resource: - !Join - '' - - !Sub 'arn:aws:codepipeline:${AWS::Region}:' - !Sub '${AWS::AccountId}:' - !Ref CodePipeline ManagedPolicyName: iam-policy-eventbridge EventBridgeIAMRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Service: - events.amazonaws.com Action: - 'sts:AssumeRole' ManagedPolicyArns: - !Ref EventBridgeIAMPolicy RoleName: iam-role-eventbridge Tags: - Key: Name Value: iam-role-eventbridge EventBridge: Type: AWS::Events::Rule Properties: Description: for codepipeline EventBusName: !GetAtt EventBus.Name EventPattern: source: - aws.codecommit detail-type: - 'CodeCommit Repository State Change' resources: - !Sub arn:aws:codecommit:${AWS::Region}:${AccountAId}:${CodeCommitName} detail: event: - referenceCreated - referenceUpdated referenceType: - branch referenceName: - main Name: eventbridge-codepipeline State: ENABLED Targets: - Arn: !Join - '' - - !Sub 'arn:aws:codepipeline:${AWS::Region}:' - !Sub '${AWS::AccountId}:' - !Ref CodePipeline Id: CodePipeline RoleArn: !GetAtt EventBridgeIAMRole.Arn
73~91行目でCodeBuildを作成しています。
96~122行目でCodeDeployを作成しています。
127~193行目でCodePipelineを作成しています。
198~280行目でEventBridgeとEventBridgeで使用するIAMロールを作成しています。
EventBridge BusはAWSアカウントAからイベントを受け取れるようにするためにAWSアカウントAからのアクセスを許可するポリシーを設定してます。(203~213行目)
デプロイは以下のAWS CLIコマンドを使用します。
aws cloudformation create-stack --stack-name CloudFormationスタック名 --template-body file://CloudFormationテンプレートファイル名 --parameters ParameterKey=CodeBuildDescription,ParameterValue=CodeBuildの説明 ParameterKey=CodeBuildName,ParameterValue=CodeBuildの名前 ParameterKey=ApplicationName,ParameterValue=CodeDeployアプリケーション名 ParameterKey=DeploymentGroupName,ParameterValue=CodeDeployデプロイグループ名 ParameterKey=KMSARN,ParameterValue=KMSキーのARN ParameterKey=CodePipelineName,ParameterValue=CodePipelineの名前 ParameterKey=CodeCommitName,ParameterValue=CodeCommitリポジトリ名 ParameterKey=CodePipelineAssumeRole,ParameterValue=AWSアカウントAで作成したCodePipelineAssumeRole ParameterKey=AccountAId,ParameterValue=AWSアカウントAのID --capabilities CAPABILITY_NAMED_IAM
動作確認
リソースの作成が完了したらappspec.yml、buildspec.yml、index.htmlを作成します。
CodeCommitリポジトリを以下のドキュメントの手順でクローンしてください。
AWS CodeCommit リポジトリに接続する
クローンしたリポジトリで以下のファイルを作成していきます。
appspec.ymlは以下の内容で作成します。
version: 0.0 os: linux files: - source: / destination: /var/www/html file_exists_behavior: OVERWRITE permissions: - object: /var/www/html owner: apache group: apache mode: 755 type: - file - directory #hooks: # デプロイする際に動かすシェルスクリプトなどを設定するセクション
buildspec.ymlは以下の内容で作成します。
version: 0.2 phases: install: on-failure: ABORT commands: - echo "install phases" - echo "yum install などでビルドに使うパッケージをインストールするのに使用" pre_build: on-failure: ABORT commands: - echo "pre_build phases" - echo "Amazon ECR にサインインしたりするのに使用" build: on-failure: ABORT commands: - echo "build phases" - echo "ビルド、テストなどを実行するのに使用" post_build: on-failure: ABORT commands: - echo "post_build phases" - echo "Docker イメージをAmazon ECR にプッシュしたりZIPとかにアーカイブするのに使用" artifacts: files: - "**/*"
index.htmlの中身は好きな内容でよいですが、今回は以下のようにしました。
<html> <head> <meta charset="UTF-8"> <title>テストページ</title> </head> <body bgcolor="#10100E" text="#cccccc"> 小林 陸<br/> </body> </html>
ディレクトリ内は以下のようになります。
ls -la total 24 drwxr-xr-x. 3 cloudshell-user cloudshell-user 4096 Mar 31 13:02 . drwxrwxrwx. 5 cloudshell-user cloudshell-user 4096 Mar 31 13:02 .. -rw-r--r--. 1 cloudshell-user cloudshell-user 360 Mar 30 16:13 appspec.yml -rw-r--r--. 1 cloudshell-user cloudshell-user 762 Mar 30 16:13 buildspec.yml drwxr-xr-x. 8 cloudshell-user cloudshell-user 4096 Mar 30 16:15 .git -rw-r--r--. 1 cloudshell-user cloudshell-user 161 Mar 31 13:02 index.html
ファイルの作成が完了したら以下のコマンドでgit push を行います。
git checkout -b mani git add . git commit -m "test" git push origin main
git pushに成功すると以下のようにCodePipelineが動きだしていることが確認できます。
デプロイが完了すると以下のようにEC2の「/var/www/html/」内にファイルが配置されることが確認できます。
ls -la /var/www/html/ total 12 drwxr-xr-x. 2 root root 64 Mar 31 13:12 . drwxr-xr-x. 4 root root 33 Mar 30 16:44 .. -rwxr-xr-x. 1 apache apache 360 Mar 31 13:11 appspec.yml -rwxr-xr-x. 1 apache apache 762 Mar 31 13:11 buildspec.yml -rwxr-xr-x. 1 apache apache 161 Mar 31 13:11 index.html
さいごに
クロスアカウントのデプロイになるとKMSやクロスアカウントロールが必要になるため設定が複雑になります。
GitHubやGitLabをご利用されている場合はCodePipelineのソースとして使用が可能なためこちらをご利用されるのもよいと思います。
GitHub 接続
GitLab セルフマネージド の接続